home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et3_0-a1.lha / et3 / src / Ink.C < prev    next >
C/C++ Source or Header  |  1992-08-26  |  15KB  |  670 lines

  1. #ifdef __GNUG__
  2. #pragma implementation
  3. #endif
  4.  
  5. #include "Ink.h"
  6.  
  7. #include "Class.h"
  8. #include "String.h"
  9. #include "Port.h"
  10. #include "WindowSystem.h"
  11. #include "Math.h"
  12. #include "OrdColl.h"
  13. #include "WindowPort.h"
  14. #include "WindowColorMap.h"
  15.  
  16. const int MaxWord1= MaxWord+1;
  17. const int cellsz= 8;
  18. const int levels= cellsz*cellsz;
  19. const int cMaxPatterns= 22;
  20.  
  21. InkManager *gInkManager;
  22.  
  23. Ink *gInkXor, *gInkNone, *gInkWhite, *gInkBlack, *gHighlightColor;   
  24. // obsolete
  25. Ink *ePatXor, *ePatNone, *ePatWhite, *ePatBlack;
  26.  
  27.  
  28. static u_short PatBits[cMaxPatterns][8]= {
  29.     { 0x8000,0x0000,0x0800,0x0000,0x8000,0x0000,0x0800,0x0000 },
  30.     { 0x8800,0x0000,0x2200,0x0000,0x8800,0x0000,0x2200,0x0000 },
  31.     { 0xaa00,0x0000,0xaa00,0x0000,0xaa00,0x0000,0xaa00,0x0000 },
  32.     { 0xaa00,0x5500,0xaa00,0x5500,0xaa00,0x5500,0xaa00,0x5500 },
  33.     { 0x5500,0xff00,0x5500,0xff00,0x5500,0xff00,0x5500,0xff00 },
  34.     { 0x7700,0xff00,0xdd00,0xff00,0x7700,0xff00,0xdd00,0xff00 },
  35.     { 0x7f00,0xff00,0xf700,0xff00,0x7f00,0xff00,0xf700,0xff00 },
  36.     { 0x9900,0xCC00,0x6600,0x3300,0x9900,0xCC00,0x6600,0x3300 },
  37.     { 0xff00,0x0000,0xff00,0x0000,0xff00,0x0000,0xff00,0x0000 },
  38.     { 0x5500,0x5500,0x5500,0x5500,0x5500,0x5500,0x5500,0x5500 },
  39.     { 0x4400,0x8800,0x1100,0x2200,0x4400,0x8800,0x1100,0x2200 },
  40.     { 0xbb00,0x7700,0xee00,0xdd00,0xbb00,0x7700,0xee00,0xdd00 },
  41.     { 0xff00,0x0000,0x0000,0x0000,0xff00,0x0000,0x0000,0x0000 },
  42.     { 0x0000,0xff00,0xff00,0xff00,0x0000,0xff00,0xff00,0xff00 },
  43.     { 0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000 },
  44.     { 0xfe00,0xfd00,0xfb00,0xf700,0xef00,0xdf00,0xbf00,0x7f00 },
  45.     { 0x5500,0x8800,0x5500,0x2200,0x5500,0x8800,0x5500,0x2200 },
  46.     { 0xaa00,0x7700,0xaa00,0xdd00,0xaa00,0x7700,0xaa00,0xdd00 },
  47.     { 0x8800,0x8800,0x8800,0x8800,0x8800,0x8800,0x8800,0x8800 },
  48.     { 0xee00,0xee00,0xee00,0xee00,0xee00,0xee00,0xee00,0xee00 },
  49.     { 0xaa00,0x5500,0xaa00,0x5500,0xaa00,0x5500,0xaa00,0x5500 },
  50.     { 0x8000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }
  51. };
  52.  
  53. static Bitmap *patterns[cMaxPatterns+1];
  54. static Bitmap **patbms;
  55. static byte *ditherm;
  56.  
  57. Ink *ePatGrey12, *ePatGrey25, *ePatGrey40, *ePatGrey50;
  58. Ink *ePatGrey60, *ePatGrey75, *ePatGrey87;
  59. Ink *ePat00, *ePat01, *ePat02, *ePat03, *ePat04, *ePat05;
  60. Ink *ePat06, *ePat07, *ePat08, *ePat09, *ePat10, *ePat11;
  61. Ink *ePat12, *ePat13, *ePat14, *ePat15;
  62.  
  63. //---- Ink ---------------------------------------------------------------------
  64.  
  65. NewMetaImpl(Ink,Object, (T(id)));
  66.  
  67. Ink::Ink()
  68. {
  69.     id= -1;
  70. }
  71.     
  72. Ink::Ink(long i)
  73. {
  74.     id= i;
  75. }
  76.  
  77. void Ink::SetId(long i)
  78. {
  79.     id= i;
  80. }
  81.  
  82. void Ink::SetInk(Port *p)
  83. {
  84.     p->DevSetOther((int)id);
  85. }
  86.  
  87. bool Ink::IsEqual(Object *op)
  88. {
  89.     return Object::IsEqual(op);
  90. }
  91.  
  92. OStream& Ink::PrintOn(OStream &s)
  93. {
  94.     Object::PrintOn(s);
  95.     return s << id SP;
  96. }
  97.  
  98. IStream& Ink::ReadFrom(IStream &s)
  99. {
  100.     Object::ReadFrom(s);
  101.     return s >> id;
  102. }
  103.  
  104. Object *Ink::ReadAndMap(IStream &is)
  105. {
  106.     if (IsA() != Meta(Ink))
  107.     return Object::ReadAndMap(is);
  108.     int id;
  109.     Object::ReadFrom(is);
  110.     
  111.     is >> id;
  112.     switch (id) {
  113.     case -1:
  114.     return gInkXor;
  115.     case 0:
  116.     return gInkNone;
  117.     case 1:
  118.     return gInkWhite;
  119.     case 2:
  120.     return gInkBlack;
  121.     default:
  122.     return new Ink(id);
  123.     }
  124. }
  125.  
  126. //---- InkManager --------------------------------------------------------------
  127.  
  128. NewMetaImpl(InkManager, Object, (TP(sharedinks)));
  129.  
  130. InkManager::InkManager()
  131. {
  132.     sharedinks= new OrdCollection;
  133.     
  134.     ePatXor= gInkXor= new Ink(-1);
  135.     sharedinks->Add(gInkXor);
  136.     ePatNone= gInkNone= new Ink((int)0);
  137.     sharedinks->Add(gInkNone);
  138.     ePatWhite= gInkWhite= new Ink(1);
  139.     sharedinks->Add(gInkWhite);
  140.     ePatBlack= gInkBlack= new Ink(2);
  141.     sharedinks->Add(gInkBlack);
  142.  
  143.     for (int i= 0; i < cMaxPatterns; i++)
  144.     patterns[i]= new Bitmap(gPoint8, PatBits[i], 1);
  145.     
  146.     ePatGrey12= patterns[0];
  147.     ePatGrey25= patterns[1];
  148.     ePatGrey40= patterns[2];
  149.     ePatGrey50= patterns[3];
  150.     ePatGrey60= patterns[4];
  151.     ePatGrey75= patterns[5];
  152.     ePatGrey87= patterns[6];    
  153.     ePat00= patterns[7];
  154.     ePat01= patterns[8];
  155.     ePat02= patterns[9];
  156.     ePat03= patterns[10];
  157.     ePat04= patterns[11];
  158.     ePat05= patterns[12];
  159.     ePat06= patterns[13];
  160.     ePat07= patterns[14];
  161.     ePat08= patterns[15];
  162.     ePat09= patterns[16];
  163.     ePat10= patterns[17];
  164.     ePat11= patterns[18];
  165.     ePat12= patterns[19];
  166.     ePat13= patterns[20];
  167.     ePat14= patterns[21];
  168.     ePat15= patterns[21];
  169. }
  170.  
  171. InkManager::~InkManager()
  172. {
  173.     gInkXor= gInkNone= gInkWhite= gInkBlack= 0;
  174.     ePatXor= ePatNone= ePatWhite= ePatBlack= 0;
  175.  
  176.     for (int i= 0; i < cMaxPatterns; i++)
  177.     SafeDelete(patterns[i]);
  178.     if (patbms) {
  179.     for (i= 0; i < levels; i++)
  180.         SafeDelete(patbms[i]);
  181.     SafeDelete(patbms);
  182.     }
  183.     SafeDelete(ditherm);
  184.     
  185.     if (sharedinks) {
  186.     sharedinks->FreeAll();
  187.     SafeDelete(sharedinks);
  188.     }
  189. }
  190.  
  191. bool InkManager::Init()
  192. {
  193.     return FALSE;
  194. }
  195.  
  196. RGBColor *new_RGBColor(short r, short g, short b, short prec)
  197. {
  198.     RGBColor *c= new RGBColor(r, g, b, prec);
  199.     gInkManager->sharedinks->Add(c);
  200.     return c;
  201. }
  202.  
  203. RGBColor *new_Grey(float graylevel, short prec)
  204. {
  205.     RGBColor *c= new RGBColor(graylevel, prec);
  206.     gInkManager->sharedinks->Add(c);
  207.     return c;
  208. }
  209.  
  210. //---- RGB ---------------------------------------------------------------------
  211.  
  212. RGB::RGB(const RGB &c)
  213. {
  214.     red= c.red;
  215.     green= c.green;
  216.     blue= c.blue;
  217. }
  218.  
  219. RGB::RGB(const HSVColor &hsv)
  220. {
  221.     register int i, f, h;
  222.     int p, q, t, hue= hsv.hue, saturation= hsv.saturation, value= hsv.value;
  223.     
  224.     if (hue > 359)
  225.     hue-= 360;
  226.     else if (hue < 0)
  227.     hue+= 360;
  228.     
  229.     if (saturation == 0)
  230.     red= green= blue= value;    // achromatic color: there is no hue
  231.     else {
  232.     h= hue * MaxWord1 / 60;
  233.     i= h / MaxWord1 * MaxWord1;
  234.     f= h - i;
  235.     p= value * (MaxWord1 - saturation) / MaxWord1;
  236.     q= value * (MaxWord1 - (saturation*f)/MaxWord1) / MaxWord1;
  237.     t= value * (MaxWord1 - (saturation * (MaxWord1 - f))/MaxWord1) / MaxWord1;
  238.     switch (i / MaxWord1) {
  239.     case 0:
  240.         red= value;     green= t;       blue= p;
  241.         break;
  242.     case 1:
  243.         red= q;         green= value;   blue= p;
  244.         break;
  245.     case 2:
  246.         red= p;         green= value;   blue= t;
  247.         break;
  248.     case 3:
  249.         red= p;         green= q;       blue= value;
  250.         break;
  251.     case 4:
  252.         red= t;         green= p;       blue= value;
  253.         break;
  254.     case 5:
  255.         red= value;     green= p;       blue= q;
  256.         break;
  257.     }
  258.     }
  259. }
  260.  
  261. RGB::RGB(float graylevel)
  262. {
  263.     red= green= blue= (short) (graylevel * MaxWord);
  264. }
  265.  
  266. void RGB::SetRGB(short r, short g, short b)
  267. {
  268.     red= Math::Range((short)0, (short)MaxWord, r);
  269.     green= Math::Range((short)0, (short)MaxWord, g);
  270.     blue= Math::Range((short)0, (short)MaxWord, b);
  271. }
  272.  
  273. short RGB::AsGreyLevel()
  274. {
  275.     int l= (int) (0.299 * red + 0.587 * green + 0.114 * blue + 0.5);
  276.     if (l > MaxWord)
  277.     return MaxWord;
  278.     return l;
  279. }
  280.  
  281. OStream& RGB::PrintOn(OStream &os)
  282. {
  283.     return os << red SP << green SP << blue SP;
  284. }
  285.  
  286. IStream& RGB::ReadFrom(IStream &is)
  287. {
  288.     return is >> red >> green >> blue;
  289. }
  290.  
  291. //---- HSVColor ----------------------------------------------------------------
  292.  
  293. HSVColor::HSVColor(const HSVColor &c)
  294. {
  295.     hue= c.hue;
  296.     saturation= c.saturation;
  297.     value= c.value;
  298. }
  299.  
  300. HSVColor::HSVColor(RGBColor &rc)
  301. {
  302.     RGB rgb(rc.rgb);
  303.     int cmax= Math::Max(Math::Max(rgb.red, rgb.green), rgb.blue);
  304.     int cmin= Math::Min(Math::Min(rgb.red, rgb.green), rgb.blue);
  305.     
  306.     value= cmax;
  307.     if (cmax)
  308.     saturation= (cmax - cmin) * MaxWord1 / cmax;
  309.     else
  310.     saturation= 0;
  311.     
  312.     if (saturation == 0)
  313.     hue= 0;
  314.     else {      // determine hue
  315.     int red_distance=   (cmax - rgb.red) * MaxWord1 / (cmax - cmin);
  316.     int green_distance= (cmax - rgb.green) * MaxWord1 / (cmax - cmin);
  317.     int blue_distance=  (cmax - rgb.blue) * MaxWord1 / (cmax - cmin);
  318.     
  319.     if (rgb.red == cmax)    // resulting color between yellow and magenta
  320.         hue= blue_distance - green_distance;
  321.     else if (rgb.green == cmax)  // resulting color between cyan and yellow
  322.         hue= 2*MaxWord1 + red_distance - blue_distance;
  323.     else                    // resulting color between magenta and cyan
  324.         hue= 4*MaxWord1 + green_distance - red_distance;
  325.         
  326.     hue= (hue * 60) / MaxWord1;      // convert to degrees
  327.     if (hue < 0)
  328.         hue+= 360;              // make nonnegative
  329.     else if (hue > 359)
  330.         hue-= 360;              // make nonnegative
  331.     }
  332. }
  333.  
  334. HSVColor::HSVColor(const RGB &rgb)
  335. {
  336.     int cmax= Math::Max(Math::Max(rgb.red, rgb.green), rgb.blue);
  337.     int cmin= Math::Min(Math::Min(rgb.red, rgb.green), rgb.blue);
  338.     
  339.     value= cmax;
  340.     if (cmax)
  341.     saturation= (cmax - cmin) * MaxWord1 / cmax;
  342.     else
  343.     saturation= 0;
  344.     
  345.     if (saturation == 0)
  346.     hue= 0;
  347.     else {      // determine hue
  348.     int red_distance=   (cmax - rgb.red) * MaxWord1 / (cmax - cmin);
  349.     int green_distance= (cmax - rgb.green) * MaxWord1 / (cmax - cmin);
  350.     int blue_distance=  (cmax - rgb.blue) * MaxWord1 / (cmax - cmin);
  351.     
  352.     if (rgb.red == cmax)    // resulting color between yellow and magenta
  353.         hue= blue_distance - green_distance;
  354.     else if (rgb.green == cmax)  // resulting color between cyan and yellow
  355.         hue= 2*MaxWord1 + red_distance - blue_distance;
  356.     else                    // resulting color between magenta and cyan
  357.         hue= 4*MaxWord1 + green_distance - red_distance;
  358.         
  359.     hue= (hue * 60) / MaxWord1;      // convert to degrees
  360.     if (hue < 0)
  361.         hue+= 360;              // make nonnegative
  362.     else if (hue > 359)
  363.         hue-= 360;              // make nonnegative
  364.     }
  365. }
  366.  
  367. OStream &HSVColor::PrintOn(OStream &s)
  368. {
  369.     return s << hue SP << saturation SP << value SP;
  370. }
  371.  
  372. IStream &HSVColor::ReadFrom(IStream &s)
  373. {
  374.     return s >> hue >> saturation >> value;
  375. }
  376.  
  377. //---- ColorMap ----------------------------------------------------------------
  378.  
  379. ColorMap::ColorMap(int sz)
  380. {
  381.     size= 0;
  382.     map= 0;
  383.     Expand(sz);
  384. }
  385.  
  386. ColorMap::ColorMap(ColorMap *cmap)
  387. {
  388.     size= 0;
  389.     map= 0;
  390.     Expand(cmap->size);
  391.     for (int i= 0; i < size; i++)
  392.     map[i]= cmap->map[i];
  393. }
  394.  
  395. ColorMap::~ColorMap()
  396. {
  397.     SafeDelete(map);
  398. }
  399.  
  400. void ColorMap::Expand(int sz)
  401. {
  402.     if (sz > size) {
  403.     map= (RGB*) Realloc(map, sz*sizeof(RGB));
  404.     size= sz;
  405.     }
  406. }
  407.  
  408. void ColorMap::SetEntry(int ix, RGB &rgb)
  409. {
  410.     Expand(ix+1);
  411.     map[ix]= rgb;
  412. }
  413.  
  414. RGB ColorMap::GetEntry(int ix)
  415. {
  416.     Expand(ix+1);
  417.     return map[ix];
  418. }
  419.  
  420. OStream& ColorMap::PrintOn(OStream &os)
  421. {
  422.     os << size;
  423.     if (size > 0) {
  424.     for (int i= 0; i < size; i++) {
  425.         if ((i % 8) == 0)
  426.         os NL;
  427.         os << map[i];
  428.     }
  429.     }
  430.     return os NL;
  431. }
  432.  
  433. IStream& ColorMap::ReadFrom(IStream &is)
  434. {
  435.     is >> size;
  436.     if (size > 0) {
  437.     Expand(size);
  438.     for (int i= 0; i < size; i++)
  439.         is >> map[i];
  440.     }
  441.     return is;
  442. }
  443.  
  444. bool ColorMap::IsGrey()
  445. {
  446.     for (int i= 0; i < size; i++)
  447.     if (! map[i].IsGrey())
  448.         return FALSE;
  449.     return TRUE;
  450. }
  451.  
  452. //---- RGBColor ----------------------------------------------------------------
  453.  
  454. NewMetaImpl(RGBColor,Ink, (T(prec)));
  455.  
  456. RGBColor::RGBColor() : rgb((short)0), Ink(-1)
  457. {
  458.     SetFlag(eInkChanged);
  459.     prec= 0;
  460.     port= 0;
  461. }
  462.  
  463. RGBColor::RGBColor(RGBColor *cp) : Ink(-1)
  464. {
  465.     SetFlag(eInkChanged);
  466.     if (cp) {
  467.     rgb= cp->rgb;
  468.     prec= cp->prec;
  469.     }
  470.     port= 0;
  471. }
  472.  
  473. RGBColor::RGBColor(short r, short g, short b, short p) : rgb(r,g,b), Ink(-1)
  474. {
  475.     SetFlag(eInkChanged);
  476.     prec= p;
  477.     port= 0;
  478. }
  479.  
  480. RGBColor::RGBColor(short graylevel, short p) : rgb(graylevel), Ink(-1)
  481. {
  482.     SetFlag(eInkChanged);
  483.     prec= p;
  484.     port= 0;
  485. }
  486.     
  487. RGBColor::RGBColor(float graylevel, short p) : rgb(graylevel), Ink(-1)
  488. {
  489.     SetFlag(eInkChanged);
  490.     prec= p;
  491.     port= 0;
  492. }
  493.  
  494. RGBColor::RGBColor(const RGB &c, short p) : rgb(c), Ink(-1)
  495. {
  496.     SetFlag(eInkChanged);
  497.     prec= p;
  498.     port= 0;
  499. }
  500.  
  501. RGBColor::RGBColor(const HSVColor &hsv, short p) : rgb(hsv), Ink(-1)
  502. {
  503.     SetFlag(eInkChanged);
  504.     prec= p;
  505.     port= 0;
  506. }
  507.  
  508. RGBColor::RGBColor(const RGBColor &rc) : rgb(rc.rgb), Ink(-1)
  509. {
  510.     SetFlag(eInkChanged);
  511.     prec= 0;
  512.     port= 0;
  513. }
  514.  
  515. bool RGBColor::SetRGB(RGB *c, short p)
  516. {
  517.     bool rc= TRUE;
  518.     
  519.     rgb= *c;
  520.     prec= Math::Range((short)0, (short)MaxWord, p);
  521.     SetFlag(eInkChanged);
  522.     if (prec == MaxWord && port) {
  523.     WindowPort *wport= (WindowPort*)port;
  524.     int newid= (int) wport->ColorMap()->AllocateAndSetCell(GetId(), c, wport);
  525.     ResetFlag(eInkChanged);
  526.     if (newid == GetId())
  527.         rc= FALSE;
  528.     SetId(newid);
  529.     }
  530.     Changed();
  531.     return rc;
  532. }
  533.  
  534. bool RGBColor::SetHSV(short hue, short sat, short value, short p)
  535. {
  536.     HSVColor hc(hue, sat, value);
  537.     RGB rc(hc);
  538.     return SetRGB(&rc, p);
  539. }
  540.  
  541. bool RGBColor::SetRGB(short r, short g, short b, short p)
  542. {
  543.     RGB rc(r, g, b);
  544.     return SetRGB(&rc, p);
  545. }
  546.  
  547. void RGBColor::SetInk(Port *p)
  548. {
  549.     port= p;
  550.     p->SetColor(this);
  551. }
  552.  
  553. OStream &RGBColor::PrintOn(OStream &s)
  554. {
  555.     Object::PrintOn(s);
  556.     return s << rgb << prec SP; 
  557. }
  558.     
  559. IStream &RGBColor::ReadFrom(IStream &s)
  560. {
  561.     Object::ReadFrom(s);
  562.     SetFlag(eInkChanged);
  563.     SetId(-1);
  564.     port= 0;
  565.     s >> rgb >> prec;
  566.     prec= 0;
  567.     return s;
  568. }
  569.     
  570. Object *RGBColor::ReadAndMap(IStream &is)
  571. {
  572.     return Object::ReadAndMap(is);
  573. }
  574.  
  575. //---- RGBColorCell ------------------------------------------------------------
  576.  
  577. NewMetaImpl0(RGBColorCell,RGBColor);
  578.  
  579. RGBColorCell::RGBColorCell(int i)
  580. {
  581.     SetId(i);
  582.     ResetFlag(eInkChanged);
  583. }
  584.  
  585. void RGBColorCell::SetInk(Port *p)
  586. {
  587.     port= p;
  588.     ResetFlag(eInkChanged);
  589.     p->SetColor(this);
  590. }
  591.  
  592. OStream& RGBColorCell::PrintOn(OStream &os)
  593. {
  594.     Object::PrintOn(os);
  595.     return os << GetId() SP;
  596. }
  597.  
  598. IStream& RGBColorCell::ReadFrom(IStream &is)
  599. {
  600.     int i;
  601.     Object::ReadFrom(is);
  602.     is >> i;
  603.     SetId(i);
  604.     return is;
  605. }
  606.  
  607. Object *RGBColorCell::ReadAndMap(IStream &is)
  608. {
  609.     return Object::ReadAndMap(is);
  610. }
  611.  
  612. //---- halftoning --------------------------------------------------------------
  613.  
  614. static void dither(int s, byte *m, int x, int y, int n);
  615.  
  616. static void dither4(int s, byte *m, int x, int y, int n, int d)
  617. {
  618.     if (n > 1) {
  619.     register int i, j;
  620.     dither(s, m, x, y, n);
  621.     for (i= x; i < x+n; i++)
  622.         for (j= y; j < y+n; j++)
  623.         m[i*s+j]= m[i*s+j]*4+d;
  624.     } else
  625.     m[x*s+y]= d;
  626. }
  627.  
  628. static void dither(int s, byte *m, int x, int y, int n)
  629. {
  630.     int n2= n/2;
  631.     dither4(s, m, x,    y,    n2, 0);
  632.     dither4(s, m, x+n2, y+n2, n2, 1);
  633.     dither4(s, m, x+n2, y,    n2, 2);
  634.     dither4(s, m, x,    y+n2, n2, 3);
  635. }
  636.  
  637. Ink *Grey2Halftone(float f)
  638. {
  639.     int level;
  640.     
  641.     if (f < 0)
  642.     f= 0.0;
  643.     else if (f > 1.0)
  644.     f= 1.0;
  645.     f= 1.0 - f;
  646.     
  647.     level= (int)(f * levels + 0.5);
  648.     if (level <= 0)
  649.     return gInkWhite;
  650.     if (level >= levels)
  651.     return gInkBlack;
  652.     if (patbms == 0) {
  653.     patbms= new Bitmap* [levels];
  654.     ditherm= new byte[levels];
  655.     dither(cellsz, ditherm, 0, 0, cellsz);
  656.     }
  657.     if (patbms[level] == 0) {
  658.     Bitmap *bm= patbms[level]= new Bitmap(cellsz, 0, 1);
  659.  
  660.     for (int y= 0; y < cellsz; y++) {
  661.         for (int x= 0; x < cellsz; x++)
  662.         if (level > ditherm[x*cellsz+y])
  663.             bm->SetPixel(x, y, 1);
  664.         else
  665.             bm->SetPixel(x, y, 0);
  666.     }
  667.     }
  668.     return patbms[level];
  669. }
  670.